/****************************************************************************
Copyright (c) 2011 The Wojo Group

thewojogroup.com
simplecartjs.com
http://github.com/thewojogroup/simplecart-js/tree/master

The MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

var Custom="Custom",GoogleCheckout="GoogleCheckout",PayPal="PayPal",Email="Email",BrazilianReal="BRL",BRL="BRL",AustralianDollar="AUD",AUD="AUD",CanadianDollar="CAD",CAD="CAD",CzechKoruna="CZK",CZK="CZK",DanishKrone="DKK",DKK="DKK",Euro="EUR",EUR="EUR",HongKongDollar="HKD",HKD="HKD",HungarianForint="HUF",HUF="HUF",IsraeliNewSheqel="ILS",ILS="ILS",JapaneseYen="JPY",JPY="JPY",MexicanPeso="MXN",MXN="MXN",NorwegianKrone="NOK",NOK="NOK",NewZealandDollar="NZD",NZD="NZD",PolishZloty="PLN",PLN="PLN",PoundSterling="GBP",GBP="GBP",SingaporeDollar="SGD",SGD="SGD",SwedishKrona="SEK",SEK="SEK",SwissFranc="CHF",CHF="CHF",ThaiBaht="THB",THB="THB",USDollar="USD",USD="USD";
function Cart(){

        var me = this;
        /* member variables */
        me.nextId = 1;
        me.Version = '2.2.3';
        me.Shelf = null;
        me.items = {};
        me.isLoaded = false;
        me.invoice = null;
        me.pageIsReady = false;
      me.minQuantityS = 0;
	me.minQuantityM = 0;
	me.minQuantityL = 0;
      me.weight = 0;
        me.quantity = 0;
	me.quantityS = 0;
	me.quantityM = 0;
	me.quantityL = 0;
        me.total = 0;
        me.taxRate = 0;
        me.taxCost = 0;
	me.shippingMethod = "air";
	me.shippingName = "air";
        me.shippingFlatRate = 0;
        me.shippingTotalRate = 0;
        me.shippingQuantityRate = 0;
   me.shippingWeightFlatRate = 0;
   me.shippingWeightFlat = 0;
   me.shippingWeightBlock = 0;
   me.shippingWeightBlockRate = 0;
   me.shippingWeightMax = 0;
        me.shippingRate = 0;
        me.shippingCost = 0;
        me.currency = USD;
        me.checkoutTo = PayPal;
	  me.emailCheckoutURL = "";	
        me.emailCheckoutString = "";
        me.email = "";
        me.merchantId    = "";
        me.successUrl = null;
        me.cancelUrl = null;
        me.cookieDuration = 30; // default duration in days
        me.storagePrefix = "sc_";
        me.MAX_COOKIE_SIZE = 4000;
        me.cartHeaders = ['Name','Price','Quantity','Total'];
        me.events = {};
        me.sandbox = false;
        me.paypalHTTPMethod = "GET";
        /*
                cart headers:
                you can set these to which ever order you would like, and the cart will display the appropriate headers
                and item info.  any field you have for the items in the cart can be used, and 'Total' will automatically
                be price*quantity.

                there are keywords that can be used:

                        1) "_input" - the field will be a text input with the value set to the given field. when the user
                                changes the value, it will update the cart.      this can be useful for quantity. (ie "Quantity_input")

                        2) "increment" - a link with "+" that will increase the item quantity by 1

                        3) "decrement" - a link with "-" that will decrease the item quantity by 1

                        4) "remove" - a link that will remove the item from the cart

                        5) "_image" or "Image" - the field will be an img tag with the src set to the value. You can simply use "Image" if
                                you set a field in the items called "Image".  If you have a field named something else, like "Thumb", you can add
                                the "_image" to create the image tag (ie "Thumb_image").

                        6) "_noHeader" - this will skip the header for that field (ie "increment_noHeader")


        */
        /******************************************************
                        function for setting options 
         ******************************************************/
        me.options = function( values ){
                me.each(values, function( value , x , name ){
                        me[name]=value;
                });
        };



        /******************************************************
                        add/remove items to cart
         ******************************************************/

        me.add = function ( values ) {
                var me=this;
                /* load cart values if not already loaded */
                if( !me.pageIsReady             ) {
                        me.initializeView();
                        me.update();
                }
                if( !me.isLoaded                ) {
                        me.load();
                        me.update();
                }

                var newItem = new CartItem();

                /* check to ensure arguments have been passed in */
                if( !arguments || arguments.length === 0 ){
                        error( 'No values passed for item.');
                        return null;
                }
                var argumentArray = arguments;
                if( values && typeof( values ) !== 'string' && typeof( values ) !== 'number'  ){
                        argumentArray = values;
                }

                newItem.parseValuesFromArray( argumentArray );
                newItem.checkQuantityAndPrice();
                
                if( me.trigger('beforeAdd', [newItem] ) === false ){
                        return false;
                }
                var isNew = true;

                /* if the item already exists, update the quantity */
                if( me.hasItem(newItem) ) {
                        var foundItem=me.hasItem(newItem);
                        foundItem.quantity= parseInt(foundItem.quantity,10) + parseInt(newItem.quantity,10);
                        newItem = foundItem;
                        isNew = false;
                } else {
                        me.items[newItem.id] = newItem;
                }

                me.update();
                me.trigger('afterAdd', [newItem,isNew] );
                
                return newItem;
                
        };


        me.remove = function( id ){
                var tempArray = {};
                        
                me.each(function(item){
                        if( item.id !== id ){
                                tempArray[item.id] = item;
                        }
                });
                this.items = tempArray;
        };

        me.empty = function () {
                me.items = {};
                me.update();
        };

        /******************************************************
                         item accessor functions
         ******************************************************/

        me.find = function (criteria) {
                if( !criteria ){
                        return null;
                }
                
                var results = [];
                        
                me.each(function(item,x,next){  
        
                        fits = true;
                
                        me.each( criteria , function(value,j,name){
                                if( !item[name] || item[name] != value ){
                                        fits = false;
                                }
                        });
                        
                        if( fits ){
                                results.push( item );
                        }
                });
                return (results.length === 0 ) ? null : results;
        };
        
        
        me.each = function( array , callback ){
                var next,
                        x=0, 
                        result;

                if( typeof array === 'function' ){
                        var cb = array
                                items = me.items;
                } else if( typeof callback === 'function' ){
                        var cb = callback,
                                items = array;
                } else {
                        return;
                }
                
                for( next in items ){
                        if( typeof items[next] !== "function" ){
                                result = cb.call( me , items[next] , x , next );
                                if( result === false ){
                                        return;
                                }
                                x++;
                        }
                }
                
        };
        
        
        me.chunk = function(str, n) {
                if (typeof n==='undefined'){ 
                        n=2;
                }
                var result = str.match(RegExp('.{1,'+n+'}','g'));
                return result || [];
        };


        /******************************************************
                         checkout management
         ******************************************************/

        me.checkout = function() {
		    me.emailCheckoutString = "";
                if( me.quantity === 0 ){
                        error("Cart is empty");
                        return;
                }
                if( me.quantityL < me.minQuantityL ){
                        alert("Please select minimum "+me.minQuantityL+" items.");
                        return;
                }
                if( me.quantityM < me.minQuantityM && me.quantityL == 0){
                        alert("Please select minimum "+me.minQuantityM+" items.");
                        return;
                }			
		    if( me.quantityS < me.minQuantityS && me.quantityM == 0 && me.quantityL == 0){
                        alert("Please select minimum "+me.minQuantityS+" items.");
                        return;
                }
			
                switch( me.checkoutTo ){
                        case PayPal:
                                me.paypalCheckout();
                                break;
                        case GoogleCheckout:
                                me.googleCheckout();
                                break;
                        case Email:
                                me.emailCheckout();
                                break;
                        default:
                                me.customCheckout();
                                break;
                }
        };

        me.paypalCheckout = function() {

                
                var form = document.createElement("form"),
                        counter=1,
                        current,
                        item,
                        descriptionString;
                        
                form.style.display = "none";
                form.method = me.paypalHTTPMethod =="GET" || me.paypalHTTPMethod == "POST" ? me.paypalHTTPMethod : "GET";
                form.action = me.sandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr" : "https://www.paypal.com/cgi-bin/webscr";
                form.acceptCharset = "utf-8";
                        
                        
                // setup hidden fields
                form.appendChild(me.createHiddenElement("cmd", "_cart"));
                form.appendChild(me.createHiddenElement("rm", me.paypalHTTPMethod == "POST" ? "2" : "0" ));
                form.appendChild(me.createHiddenElement("upload", "1"));
                form.appendChild(me.createHiddenElement("business", me.email ));
                form.appendChild(me.createHiddenElement("currency_code", me.currency));
                form.appendChild(me.createHiddenElement("charset", "utf-8"));

                if (me.invoice) {
                    form.appendChild(me.createHiddenElement("invoice", me.invoice));
                }

                if( me.taxRate ){
                        form.appendChild(me.createHiddenElement("tax_cart", parseFloat(me.taxCost).toFixed(2)));
                }
                
                if( me.shipping() !== 0){
                        form.appendChild(me.createHiddenElement("handling_cart",  me.shippingCost ));
                }
                
                if( me.successUrl ){
                        form.appendChild(me.createHiddenElement("return",  me.successUrl ));
                }
                
                if( me.cancelUrl ){
                        form.appendChild(me.createHiddenElement("cancel_return",  me.cancelUrl ));
                }
                
                

                me.each(function(item,iter){

                        counter = iter+1;
                
                        form.appendChild( me.createHiddenElement( "item_name_"          + counter, item.name            ) );
                        form.appendChild( me.createHiddenElement( "quantity_"           + counter, item.quantity        ) );
                        form.appendChild( me.createHiddenElement( "amount_"                     + counter, item.price           ) );
                        form.appendChild( me.createHiddenElement( "weight_"                     + counter, item.weight          ) );
                        form.appendChild( me.createHiddenElement( "item_number_"        + counter, counter                      ) );
                        
                        var option_count = 0;

                        me.each( item , function( value, x , field ){
                                if( field !== "id" && field !== "price" && field !== "weight" && field !== "quantity" && field !== "name" && field !== "shipping" && option_count < 10) {
                                        form.appendChild( me.createHiddenElement( "on" + option_count + "_"     + counter,      field ) );
                                        form.appendChild( me.createHiddenElement( "os" + option_count + "_"     + counter,      value ) );
                                        option_count++;
                                }
                        });

                        form.appendChild( me.createHiddenElement( "option_index_" + counter, option_count) );

                });


                document.body.appendChild( form );
                form.submit();
                document.body.removeChild( form );
                
        };

        me.googleCheckout = function() {
                var me = this;
                
                
                if( me.currency !== USD && me.currency !== GBP ){
                        error( "Google Checkout only allows the USD and GBP for currency.");
                        return;
                } else if( me.merchantId === "" || me.merchantId === null || !me.merchantId ){
                        error( "No merchant Id for google checkout supplied.");
                        return;
                }

                var form = document.createElement("form"),
                        counter=1,
                        current,
                        item,
                        descriptionString;
                        
                form.style.display = "none";
                form.method = "POST";
                form.action = "https://checkout.google.com/api/checkout/v2/checkoutForm/Merchant/" +
                                                me.merchantId;
                form.acceptCharset = "utf-8";

                me.each(function(item,iter){
                                
                        counter = iter+1;
                
                        form.appendChild( me.createHiddenElement( "item_name_"          + counter, item.name            ) );
                        form.appendChild( me.createHiddenElement( "item_quantity_"      + counter, item.quantity        ) );
                        form.appendChild( me.createHiddenElement( "item_price_"         + counter, item.price           ) );
                        form.appendChild( me.createHiddenElement( "item_weight_"                + counter, item.weight          ) );
                        form.appendChild( me.createHiddenElement( "item_currency_"      + counter, me.currency          ) );
                        form.appendChild( me.createHiddenElement( "item_tax_rate_"      + counter, me.taxRate           ) );
                        form.appendChild( me.createHiddenElement( "_charset_"                            , ""                           ) );

                        descriptionString = "";

                        me.each( item , function( value , x , field ){
                        
                                if( field !== "id"              &&
                                        field !== "quantity" &&
                   field !== "weight" &&
                                        field !== "price" ) {
                                                
                                                descriptionString = descriptionString + ", " + field + ": " + value;
                                }
                        });
                        
                        descriptionString = descriptionString.substring( 1 );
                        form.appendChild( me.createHiddenElement( "item_description_" + counter, descriptionString) );

                });
                
                // hack for adding shipping
                if( me.shipping() !== 0){
                   form.appendChild(me.createHiddenElement("ship_method_name_1", "Shipping"));
                   form.appendChild(me.createHiddenElement("ship_method_price_1", parseFloat(me.shippingCost).toFixed(2)));
                   form.appendChild(me.createHiddenElement("ship_method_currency_1", me.currency));
                }

                document.body.appendChild( form );
                form.submit();
                document.body.removeChild( form );
        };



        me.emailCheckout = function() {
		if(document.location.href != me.emailCheckoutURL) {
			if(document.location.href != me.emailCheckoutURL+"#")
            		document.location.href = me.emailCheckoutURL;
		}

 		for( var current in me.items ){ 
        		var item = me.items[current];
        		me.emailCheckoutString += "Item Name:"+item.name + "\n"; 
			me.emailCheckoutString += "Item Size:"+item.size + "\n"; 
			me.emailCheckoutString += "Quantity :"+item.quantity + "\n"; 
			me.emailCheckoutString += "Price    :$"+item.price + "\n\n";
	      }
     me.emailCheckoutString += "Item Total :$"+ me.total + "\n";
 		me.emailCheckoutString += me.shippingName + "-" + me.shippingMethod + ":$" + me.shippingCost + "\n";
     me.emailCheckoutString += "Grand Total :$"+ Math.round(me.finalTotal*Math.pow(10,2))/Math.pow(10,2);
        };

        me.customCheckout = function() {
                return;
        };




        /******************************************************
                                data storage and retrival
         ******************************************************/

        /* load cart from cookie */
        me.load = function () {
                
                var me = this,
                        id;
                        
                /* initialize variables and items array */
                me.items = {};
                me.total = 0.00;
                me.quantity = 0;

                /* retrieve item data from cookie */
                /* v2.2.2 code 
                if( readCookie(simpleCart.storagePrefix + 'simpleCart_' + "chunks") ){
                        var chunkCount = 1*readCookie(simpleCart.storagePrefix + 'simpleCart_' + "chunks"),
                                dataArray = [],
                                dataString = "",
                                data = "",
                                info,
                                newItem,
                                y=0;
                        if(chunkCount>0) {      
                                for( y=0;y<chunkCount;y++){
                                        dataArray.push( readCookie( simpleCart.storagePrefix + 'simpleCart_' + (1 + y ) ) );
                                }
                        
                                dataString = unescape( dataArray.join("") );
                                data = dataString.split("++");
                        }
                        for(var x=0, xlen=data.length;x<xlen;x++){

                                info = data[x].split('||');
                                newItem = new CartItem();

                                if( newItem.parseValuesFromArray( info ) ){
                                        newItem.checkQuantityAndPrice();
                                        // store the new item in the cart 
                                        me.items[newItem.id] = newItem;
                                }
                        }
                }
                */
                
                /* code from v3 */
                var items = unescape( localStorage.getItem( simpleCart.storagePrefix + "simpleCart_items" ) );
                
                if( items ){
                
                        simpleCart.each( JSON.parse( items ) ,function( item , x , id ){
                                var newItem = new CartItem(),
                                        attrs = [];
                                newItem.id = id;
                                
                                
                        
                                // add all the values
                                simpleCart.each( item , function( val , x , name ){
                                        attrs.push( name + "=" + val );
                                });
                                
                                if( newItem.parseValuesFromArray( attrs ) ){
                                        newItem.checkQuantityAndPrice();
                                        // store the new item in the cart 
                                        me.items[newItem.id] = newItem;
                                }
                        });
                
                }
        
                me.isLoaded = true;
        };



        /* save cart to cookie */
        me.save = function () {
                /* v2.2.2 code 
                var dataString = "",
                        dataArray = [],
                        chunkCount = 0;
                        
                chunkCount = 1*readCookie(simpleCart.storagePrefix + 'simpleCart_' + "chunks");
                for( var j=0;j<chunkCount;j++){
                        eraseCookie(simpleCart.storagePrefix + 'simpleCart_'+ j);
                }
                eraseCookie(simpleCart.storagePrefix + 'simpleCart_' + "chunks");
                
                        
                me.each(function(item){
                        dataString = dataString + "++" + item.print();
                });
                
                dataArray = simpleCart.chunk( dataString.substring(2) , simpleCart.MAX_COOKIE_SIZE );
                
                for( var x=0,xlen = dataArray.length;x<xlen;x++){
                        createCookie(simpleCart.storagePrefix + 'simpleCart_' + (1 + x ), dataArray[x], me.cookieDuration );
                }
                                
                createCookie( simpleCart.storagePrefix + 'simpleCart_' + "chunks", "" + dataArray.length , me.cookieDuration );
                */
                
                /* using code from v3 */                
                var items = {};
                
                // save all the items
                simpleCart.each(function(item){
                        items[item.id] = {};
                        simpleCart.each( item , function( value , x , name ){
                                if( name !== "id" ){
                                        items[item.id][name] = value;
                                }
                        });
                });
                
                localStorage.setItem( simpleCart.storagePrefix + "simpleCart_items" , escape( JSON.stringify( items ) ) );
                
        };



        /******************************************************
                                 view management
         ******************************************************/

        me.initializeView = function() {
                var me = this;
                me.totalOutlets                         = getElementsByClassName('simpleCart_total');
        me.weightOutlets                        = getElementsByClassName('simpleCart_weight');
                me.quantityOutlets                      = getElementsByClassName('simpleCart_quantity');
                me.cartDivs                                     = getElementsByClassName('simpleCart_items');
                me.taxCostOutlets                       = getElementsByClassName('simpleCart_taxCost');
                me.taxRateOutlets                       = getElementsByClassName('simpleCart_taxRate');
                me.shippingCostOutlets          = getElementsByClassName('simpleCart_shippingCost');
                me.finalTotalOutlets            = getElementsByClassName('simpleCart_finalTotal');

                me.addEventToArray( getElementsByClassName('simpleCart_checkout') , simpleCart.checkout , "click");
                me.addEventToArray( getElementsByClassName('simpleCart_empty')  , simpleCart.empty , "click" );
                
                me.Shelf = new Shelf();
                me.Shelf.readPage();

                me.pageIsReady = true;

        };



        me.updateView = function() {
                me.updateViewTotals();
                if( me.cartDivs && me.cartDivs.length > 0 ){
                        me.updateCartView();
                }
        };

        me.updateViewTotals = function() {
                var outlets = [ ["quantity"             , "none"                ] ,
                        ["weight"               , "none"        ] ,
                                                ["total"                , "currency"    ] ,
                                                ["shippingCost" , "currency"    ] ,
                                                ["taxCost"              , "currency"    ] ,
                                                ["taxRate"              , "percentage"  ] ,
                                                ["finalTotal"   , "currency"    ] ];

                for( var x=0,xlen=outlets.length; x<xlen;x++){

                        var arrayName = outlets[x][0] + "Outlets",
                                outputString,
                                element;

                        for( var y = 0,ylen = me[ arrayName ].length; y<ylen; y++ ){ 
                                switch( outlets[x][1] ){
                                        case "none":
                                                outputString = "" + me[outlets[x][0]];
                                                break;
                                        case "currency":
                                                outputString = me.valueToCurrencyString( me[outlets[x][0]] );
                                                break;
                                        case "percentage":
                                                outputString = me.valueToPercentageString( me[outlets[x][0]] );
                                                break;
                                        default:
                                                outputString = "" + me[outlets[x][0]];
                                                break;
                                }
                                me[arrayName][y].innerHTML = "" + outputString;
                        }
                }
        };

        me.updateCartView = function() {
                var newRows = [],
                        y,newRow,current,header,newCell,info,outputValue,option,headerInfo;

                /* create headers row */
                newRow = document.createElement('div');
                for(var y=0,ylen = me.cartHeaders.length; y<ylen; y++ ){
                        newCell = document.createElement('div');
                        headerInfo = me.cartHeaders[y].split("_");

                        newCell.innerHTML = me.print( headerInfo[0] );
                        newCell.className = "item" + headerInfo[0];
                        for(var z=1,zlen=headerInfo.length;z<zlen;z++){
                                if( headerInfo[z].toLowerCase() == "noheader" ){
                                        newCell.style.display = "none";
                                }
                        }
                        newRow.appendChild( newCell );

                }
                newRow.className = "cartHeaders";
                newRows[0] = newRow;

                /* create a row for each item in the cart */
                me.each(function(item, x){
                        newRow = document.createElement('div');

                        for(var y=0,ylen = me.cartHeaders.length; y<ylen; y++ ){
                                newCell = document.createElement('div');
                                info = me.cartHeaders[y].split("_");
                        
                                outputValue = me.createCartRow( info , item , outputValue );

                                newCell.innerHTML = outputValue;
                                newCell.className = "item" + info[0];
                        
                                newRow.appendChild( newCell );
                        }
                        newRow.className = "itemContainer";
                        newRows[x+1] = newRow;
                });



                for( var x=0,xlen=me.cartDivs.length; x<xlen; x++){

                        /* delete current rows in div */
                        var div = me.cartDivs[x];
                        if( div.childNodes && div.appendChild ){
                                while( div.childNodes[0] ){
                                        div.removeChild( div.childNodes[0] );
                                }
                        

                                for(var j=0, jLen = newRows.length; j<jLen; j++){
                                        div.appendChild( newRows[j] );
                                }
                        }

                }
        };
        
        me.createCartRow = function( info , item , outputValue ){
                                
                switch( info[0].toLowerCase() ){
                        case "total":
                                outputValue = me.valueToCurrencyString(parseFloat(item.price)*parseInt(item.quantity,10) );
                                break;
                        case "increment":
                                outputValue = me.valueToLink( "+" , "javascript:;" , "onclick=\"simpleCart.items[\'" + item.id + "\'].increment();\"" );
                                break;
                        case "decrement":
                                outputValue = me.valueToLink( "-" , "javascript:;" , "onclick=\"simpleCart.items[\'" + item.id + "\'].decrement();\"" );
                                break;
                        case "remove":
                                outputValue = me.valueToLink( "Remove" , "javascript:;" , "onclick=\"simpleCart.items[\'" + item.id + "\'].remove();\"" );
                                break;
                        case "price":
                                outputValue = me.valueToCurrencyString( item[ info[0].toLowerCase() ] ? item[info[0].toLowerCase()] : " " );
                                break;
                        default: 
                                outputValue = item[ info[0].toLowerCase() ] ? 
                                                        typeof  item[info[0].toLowerCase()] === 'function' ?
                                                                        item[info[0].toLowerCase()].call(item) :
                                                                        item[info[0].toLowerCase()] :
                                                                        " ";
                                break;
                }       
                
                for( var y=1,ylen=info.length;y<ylen;y++){
                        option = info[y].toLowerCase();
                        switch( option ){
                                case "image":
                                case "img":
                                        outputValue = me.valueToImageString( outputValue );             
                                        break;
                                case "input":
                                        outputValue = me.valueToTextInput( outputValue , "onchange=\"simpleCart.items[\'" + item.id + "\'].set(\'" + info[0].toLowerCase() + "\' , this.value);\""      );
                                        break;
                                case "div":
                                case "span":
                                case "h1":
                                case "h2":
                                case "h3":
                                case "h4":
                                case "p":
                                        outputValue = me.valueToElement( option , outputValue , "" );
                                        break;
                                case "noheader":
                                        break;
                                default:
                                        error( "unkown header option: " + option );
                                        break;
                        }
                
                }                 
                return outputValue;
        };

        me.addEventToArray = function ( array , functionCall , theEvent ) {
                var outlet, 
                        element;
                
                for(var x=0,xlen=array.length; x<xlen; x++ ){
                        element = array[x];
                        if( element.addEventListener ) {
                                element.addEventListener(theEvent, functionCall , false );
                        } else if( element.attachEvent ) {
                                element.attachEvent( "on" + theEvent, functionCall );
                        }
                }
        };


        me.createHiddenElement = function ( name , value ){
                var element = document.createElement("input");
                element.type = "hidden";
                element.name = name;
                element.value = value;
                return element;
        };


        /******************************************************
                        Event Management
         ******************************************************/
        
        // bind a callback to a simpleCart event
        me.bind = function( name , callback ){
                if( typeof callback !== 'function' ){
                        return me;
                }
                
                
                if (me.events[name] === true ){
                        callback.apply( me );
                } else if( typeof me.events[name] !== 'undefined' ){
                        me.events[name].push( callback );
                } else {
                        me.events[name] = [ callback ];
                }
                return me;
        };
        
        
        // trigger event
        me.trigger = function( name , options ){
                var returnval = true;
                if( typeof me.events[name] !== 'undefined' && typeof me.events[name][0] === 'function'){
                        for( var x=0,xlen=me.events[name].length; x<xlen; x++ ){
                                returnval = me.events[name][x].apply( me , (options ? options : [] ) );
                        }
                }
                if( returnval === false ){
                        return false;
                } else {
                        return true;
                }
        };
        
        // shortcut for ready function
        me.ready = function( callback ){
                if( !callback ){
                        me.trigger( 'ready' );
                        me.events['ready'] = true;
                } else {
                        me.bind( 'ready' , callback );
                }
                return me;
        };




        /******************************************************
                                Currency management
         ******************************************************/

        me.currencySymbol = function() {
                switch(me.currency){
                        case CHF:
                                return "CHF&nbsp;";
                        case CZK:
                                return "CZK&nbsp;";
                        case DKK:
                                return "DKK&nbsp;";
                        case HUF:
                                return "HUF&nbsp;";
                        case NOK:
                                return "NOK&nbsp;";
                        case PLN:
                                return "PLN&nbsp;";
                        case SEK:
                                return "SEK&nbsp;";
                        case JPY:
                                return "&yen;";
                        case EUR:
                                return "&euro;";
                        case GBP:
                                return "&pound;";
                        case CHF:
                                return "CHF&nbsp;";
                        case THB: 
                                return "&#3647;";
                        case USD:
                        case CAD:
                        case AUD:
                        case NZD:
                        case HKD:
                                return "HK&#36;";
                        case SGD:
                                return "&#36;";
                        default:
                                return "";
                }
        };


        me.currencyStringForPaypalCheckout = function( value ){
                if( me.currencySymbol() == "&#36;" ){
                        return "$" + parseFloat( value ).toFixed(2);
                } else {
                        return "" + parseFloat(value ).toFixed(2);
                }
        };

        /******************************************************
                                Formatting
         ******************************************************/


        me.valueToCurrencyString = function( value ) {
                var val =  parseFloat( value ); 
                if( isNaN(val))
                        val = 0;

                return val.toCurrency( me.currencySymbol() );
        };

        me.valueToPercentageString = function( value ){
                return parseFloat( 100*value ) + "%";
        };

        me.valueToImageString = function( value ){
                if( value.match(/<\s*img.*src\=/) ){
                        return value;
                } else {
                        return "<img src=\"" + value + "\" />";
                }
        };

        me.valueToTextInput = function( value , html ){
                return "<input type=\"text\" value=\"" + value + "\" " + html + " />";
        };

        me.valueToLink = function( value, link, html){
                return "<a href=\"" + link + "\" " + html + " >" + value + "</a>";
        };

        me.valueToElement = function( type , value , html ){
                return "<" + type + " " + html + " > " + value + "</" + type + ">";
        };

        /******************************************************
                                Duplicate management
         ******************************************************/

        me.hasItem = function ( item ) {
                var current, 
                        matches,
                        field,
                        match=false;
                
                me.each(function(testItem){ 
                        
                        matches = true;
                        
                        me.each( item , function( value , x , field ){ 
                                
                                if( field !== "quantity" && field !== "id" && item[field] !== testItem[field] ){
                                        matches = false;
                                }
                        });
                        
                        if( matches ){
                                match = testItem;
                        }
                        
                });
                return match;
        };
        
        /******************************************************
                                Language managment
         ******************************************************/
        me.ln = {
                "en_us": {
                          quantity: "Quantity"
                        , price: "Price"
           , weight: "Weight"
                        , total: "Total"
                        , decrement: "Decrement"
                        , increment: "Increment"
                        , remove: "Remove"
                        , tax: "Tax"
                        , shipping: "Shipping"
                        , image: "Image"
                } 
        };
        
        me.language = "en_us"; 
        
        me.print = function( input ) {
                var me = this;
                return me.ln[me.language] && me.ln[me.language][input.toLowerCase()] ? me.ln[me.language][input.toLowerCase()] : input;
                
        };


        /******************************************************
                                Cart Update managment
         ******************************************************/

        me.update = function() {
                if( !simpleCart.isLoaded ){
                        simpleCart.load();
                }
                if( !simpleCart.pageIsReady ){
                        simpleCart.initializeView();
                }
                me.updateTotals();
                me.updateView();
                me.save();
        };

        me.updateTotals = function() {
                        
                me.total = 0 ;
                me.quantity      = 0;
		    me.quantityS      = 0;
		    me.quantityM      = 0;
		    me.quantityL      = 0;
      	    me.weight = 0;
                me.each(function(item){ 
                        if( item.quantity < 1 ){
                                item.remove();
                        } else if( item.quantity !== null && item.quantity !== "undefined" ){
                                me.quantity = parseInt(me.quantity,10) + parseInt(item.quantity,10);
					  if (item.size == "S")
						me.quantityS = parseInt(me.quantityS,10) + parseInt(item.quantity,10);
					  else if (item.size == "M")
						me.quantityM = parseInt(me.quantityM,10) + parseInt(item.quantity,10);
					  else if (item.size == "L")
						me.quantityL = parseInt(me.quantityL,10) + parseInt(item.quantity,10);
                        }

                        if( item.price ){
                                me.total = parseFloat(me.total) + parseInt(item.quantity,10)*parseFloat(item.price);
                        }
           if( item.weight ){
                                me.weight = parseInt(me.weight,10) + parseInt(item.quantity,10)*parseInt(item.weight,10);
                        }

                        
                });
                me.shippingCost = me.shipping();
                me.taxCost = parseFloat(me.total)*me.taxRate;
                me.finalTotal = me.shippingCost + me.taxCost + me.total;
        };
	
	  me.shippingRate = function() {
    if(me.shippingMethod == "hklocal")  {
      /*Hong Kong*/
      me.shippingName = "HKLocal";
      me.shippingFlatRate = 0;
		me.shippingWeightFlatRate = 0;
      me.shippingWeightFlat = 0;
	   me.shippingWeightBlockRate = 0;
      me.shippingWeightBlock = 0;
      me.shippingWeightMax = 0;
	
	var shippingWeightHK = parseInt(me.weight,10);
	while (shippingWeightHK > 0) {
		if (shippingWeightHK > 0 && shippingWeightHK <= 30) me.shippingFlatRate += parseFloat(1.7);
else if (shippingWeightHK > 30 && shippingWeightHK <= 50) me.shippingFlatRate += parseFloat(2.7);
else if (shippingWeightHK > 50 && shippingWeightHK <= 100) me.shippingFlatRate += parseFloat(3.7);
else if (shippingWeightHK > 100 && shippingWeightHK <= 150) me.shippingFlatRate += parseFloat(4.5);
else if (shippingWeightHK > 150 && shippingWeightHK <= 200) me.shippingFlatRate += parseFloat(4.9);
else if (shippingWeightHK > 200 && shippingWeightHK <= 250) me.shippingFlatRate += parseFloat(5.4);
else if (shippingWeightHK > 250 && shippingWeightHK <= 500) me.shippingFlatRate += parseFloat(10);
else if (shippingWeightHK > 500 && shippingWeightHK <= 1000) me.shippingFlatRate += parseFloat(20);
else if (shippingWeightHK > 1000 && shippingWeightHK <= 2000) me.shippingFlatRate += parseFloat(34.2);
else if (shippingWeightHK > 2000 && shippingWeightHK <= 3000) me.shippingFlatRate += parseFloat(55);
else if (shippingWeightHK > 3000 && shippingWeightHK <= 4000) me.shippingFlatRate += parseFloat(66);
else if (shippingWeightHK > 4000 && shippingWeightHK <= 5000) me.shippingFlatRate += parseFloat(78);
else if (shippingWeightHK > 5000 && shippingWeightHK <= 6000) me.shippingFlatRate += parseFloat(89);
else if (shippingWeightHK > 6000 && shippingWeightHK <= 7000) me.shippingFlatRate += parseFloat(101);
else if (shippingWeightHK > 7000 && shippingWeightHK <= 8000) me.shippingFlatRate += parseFloat(113);
else if (shippingWeightHK > 8000 && shippingWeightHK <= 9000) me.shippingFlatRate += parseFloat(124);
else if (shippingWeightHK > 9000 && shippingWeightHK <= 10000) me.shippingFlatRate += parseFloat(136);
else if (shippingWeightHK > 10000 && shippingWeightHK <= 11000) me.shippingFlatRate += parseFloat(147);
else if (shippingWeightHK > 11000 && shippingWeightHK <= 12000) me.shippingFlatRate += parseFloat(159);
else if (shippingWeightHK > 12000 && shippingWeightHK <= 13000) me.shippingFlatRate += parseFloat(171);
else if (shippingWeightHK > 13000 && shippingWeightHK <= 14000) me.shippingFlatRate += parseFloat(182);
else if (shippingWeightHK > 14000 && shippingWeightHK <= 15000) me.shippingFlatRate += parseFloat(194);
else if (shippingWeightHK > 15000 && shippingWeightHK <= 16000) me.shippingFlatRate += parseFloat(205);
else if (shippingWeightHK > 16000 && shippingWeightHK <= 17000) me.shippingFlatRate += parseFloat(217);
else if (shippingWeightHK > 17000 && shippingWeightHK <= 18000) me.shippingFlatRate += parseFloat(229);
else if (shippingWeightHK > 18000 && shippingWeightHK <= 19000) me.shippingFlatRate += parseFloat(240);
else if (shippingWeightHK > 19000) me.shippingFlatRate += parseFloat(252);

     /*Box charges*/
     if (shippingWeightHK > 0 && shippingWeightHK <= 2000) me.shippingFlatRate += parseFloat(13);
     else if (shippingWeightHK > 2000) me.shippingFlatRate += parseFloat(17);

		shippingWeightHK = parseInt(shippingWeightHK,10) - 20000;
	}
    }   
		else if(me.shippingMethod == "surface") {
			/*Singpost*/
			if (me.weight <= 20) {
				me.shippingName = "Singpost 20";
				me.shippingFlatRate = 0;				
		  		me.shippingWeightFlatRate = 3.1;
	                	me.shippingWeightFlat = 20;
       	         	me.shippingWeightBlockRate = 6.2;
              	  	me.shippingWeightBlock = 100;
                		me.shippingWeightMax = 2000;
			}
			else if (me.weight <= 50) {
				me.shippingName = "Singpost 50";
				me.shippingFlatRate = 0;
		  		me.shippingWeightFlatRate = 4.34;
	                	me.shippingWeightFlat = 50;
       	         	me.shippingWeightBlockRate = 6.2;
              	  	me.shippingWeightBlock = 100;
                		me.shippingWeightMax = 2000;
			}
			else {
				me.shippingName = "Singpost 100";
				me.shippingFlatRate = 0;
		  		me.shippingWeightFlatRate = 6.2;
                		me.shippingWeightFlat = 100;
                		me.shippingWeightBlockRate = 6.2;
                		me.shippingWeightBlock = 100;
                		me.shippingWeightMax = 2000;
			}
		}
		else if(me.shippingMethod == "air") {
			/*Singpost*/
			if (me.weight <= 880) {
				me.shippingName = "Singpost";
				me.shippingFlatRate = 0;
		    		me.shippingWeightFlatRate = 4.03;
                		me.shippingWeightFlat = 20;
	                  me.shippingWeightBlockRate = 1.55;
         		      me.shippingWeightBlock = 10;
                		me.shippingWeightMax = 880;
			}
			/*Speedpost*/
			else {
				me.shippingName = "Speedpost";
				me.shippingFlatRate = 0;
		    		me.shippingWeightFlatRate = 0;
                		me.shippingWeightFlat = 0;
	                  me.shippingWeightBlockRate = 0;
         		      me.shippingWeightBlock = 0;
                		me.shippingWeightMax = 0;
				
				var shippingWeight = parseInt(me.weight,10);
				while (shippingWeight > 0) {
					if (shippingWeight > 0 && shippingWeight <= 500) me.shippingFlatRate += parseFloat(110.98);
					else if (shippingWeight > 500 && shippingWeight <= 1000) me.shippingFlatRate += parseFloat(137.33);
					else if (shippingWeight > 1000 && shippingWeight <= 1500) me.shippingFlatRate += parseFloat(163.68);
					else if (shippingWeight > 1500 && shippingWeight <= 2000) me.shippingFlatRate += parseFloat(190.34);
					else if (shippingWeight > 2000 && shippingWeight <= 2500) me.shippingFlatRate += parseFloat(216.69);
					else if (shippingWeight > 2500 && shippingWeight <= 3000) me.shippingFlatRate += parseFloat(243.04);
					else if (shippingWeight > 3000 && shippingWeight <= 3500) me.shippingFlatRate += parseFloat(269.39);
					else if (shippingWeight > 3500 && shippingWeight <= 4000) me.shippingFlatRate += parseFloat(296.05);
					else if (shippingWeight > 4000 && shippingWeight <= 4500) me.shippingFlatRate += parseFloat(322.4);
					else if (shippingWeight > 4500 && shippingWeight <= 5000) me.shippingFlatRate += parseFloat(348.75);
					else if (shippingWeight > 5000 && shippingWeight <= 5500) me.shippingFlatRate += parseFloat(375.41);
					else if (shippingWeight > 5500 && shippingWeight <= 6000) me.shippingFlatRate += parseFloat(401.76);
					else if (shippingWeight > 6000 && shippingWeight <= 6500) me.shippingFlatRate += parseFloat(428.11);
					else if (shippingWeight > 6500 && shippingWeight <= 7000) me.shippingFlatRate += parseFloat(454.46);
					else if (shippingWeight > 7000 && shippingWeight <= 7500) me.shippingFlatRate += parseFloat(481.12);
					else if (shippingWeight > 7500 && shippingWeight <= 8000) me.shippingFlatRate += parseFloat(507.47);
					else if (shippingWeight > 8000 && shippingWeight <= 8500) me.shippingFlatRate += parseFloat(533.82);
					else if (shippingWeight > 8500 && shippingWeight <= 9000) me.shippingFlatRate += parseFloat(560.17);
					else if (shippingWeight > 9000 && shippingWeight <= 9500) me.shippingFlatRate += parseFloat(586.83);
					else if (shippingWeight > 9500 && shippingWeight <= 10000) me.shippingFlatRate += parseFloat(613.18);
					else if (shippingWeight > 10000 && shippingWeight <= 10500) me.shippingFlatRate += parseFloat(639.53);
					else if (shippingWeight > 10500 && shippingWeight <= 11000) me.shippingFlatRate += parseFloat(666.19);
					else if (shippingWeight > 11000 && shippingWeight <= 11500) me.shippingFlatRate += parseFloat(692.54);
					else if (shippingWeight > 11500 && shippingWeight <= 12000) me.shippingFlatRate += parseFloat(719.2);
					else if (shippingWeight > 12000 && shippingWeight <= 12500) me.shippingFlatRate += parseFloat(745.24);
					else if (shippingWeight > 12500 && shippingWeight <= 13000) me.shippingFlatRate += parseFloat(772.21);
					else if (shippingWeight > 13000 && shippingWeight <= 13500) me.shippingFlatRate += parseFloat(798.25);
					else if (shippingWeight > 13500 && shippingWeight <= 14000) me.shippingFlatRate += parseFloat(824.91);
					else if (shippingWeight > 14000 && shippingWeight <= 14500) me.shippingFlatRate += parseFloat(850.95);
					else if (shippingWeight > 14500 && shippingWeight <= 15000) me.shippingFlatRate += parseFloat(877.92);
					else if (shippingWeight > 15000 && shippingWeight <= 15500) me.shippingFlatRate += parseFloat(903.96);
					else if (shippingWeight > 15500 && shippingWeight <= 16000) me.shippingFlatRate += parseFloat(930.62);
					else if (shippingWeight > 16000 && shippingWeight <= 16500) me.shippingFlatRate += parseFloat(957.28);
					else if (shippingWeight > 16500 && shippingWeight <= 17000) me.shippingFlatRate += parseFloat(983.63);
					else if (shippingWeight > 17000 && shippingWeight <= 17500) me.shippingFlatRate += parseFloat(1009.67);
					else if (shippingWeight > 17500 && shippingWeight <= 18000) me.shippingFlatRate += parseFloat(1036.33);
					else if (shippingWeight > 18000 && shippingWeight <= 18500) me.shippingFlatRate += parseFloat(1062.99);
					else if (shippingWeight > 18500 && shippingWeight <= 19000) me.shippingFlatRate += parseFloat(1089.34);
					else if (shippingWeight > 19000 && shippingWeight <= 19500) me.shippingFlatRate += parseFloat(1115.38);
					else if (shippingWeight > 19500 && shippingWeight <= 20000) me.shippingFlatRate += parseFloat(1142.35);
					else if (shippingWeight > 20000 && shippingWeight <= 20500) me.shippingFlatRate += parseFloat(1168.7);
					else if (shippingWeight > 20500 && shippingWeight <= 21000) me.shippingFlatRate += parseFloat(1195.05);
					else if (shippingWeight > 21000 && shippingWeight <= 21500) me.shippingFlatRate += parseFloat(1221.09);
					else if (shippingWeight > 21500 && shippingWeight <= 22000) me.shippingFlatRate += parseFloat(1248.06);
					else if (shippingWeight > 22000 && shippingWeight <= 22500) me.shippingFlatRate += parseFloat(1274.41);
					else if (shippingWeight > 22500 && shippingWeight <= 23000) me.shippingFlatRate += parseFloat(1300.76);
					else if (shippingWeight > 23000 && shippingWeight <= 23500) me.shippingFlatRate += parseFloat(1326.8);
					else if (shippingWeight > 23500 && shippingWeight <= 24000) me.shippingFlatRate += parseFloat(1353.77);
					else if (shippingWeight > 24000 && shippingWeight <= 24500) me.shippingFlatRate += parseFloat(1380.43);
					else if (shippingWeight > 24500 && shippingWeight <= 25000) me.shippingFlatRate += parseFloat(1406.47);
					else if (shippingWeight > 25000 && shippingWeight <= 25500) me.shippingFlatRate += parseFloat(1433.44);
					else if (shippingWeight > 25500 && shippingWeight <= 26000) me.shippingFlatRate += parseFloat(1459.48);
					else if (shippingWeight > 26000 && shippingWeight <= 26500) me.shippingFlatRate += parseFloat(1486.14);
					else if (shippingWeight > 26500 && shippingWeight <= 27000) me.shippingFlatRate += parseFloat(1512.18);
					else if (shippingWeight > 27000 && shippingWeight <= 27500) me.shippingFlatRate += parseFloat(1539.15);
					else if (shippingWeight > 27500 && shippingWeight <= 28000) me.shippingFlatRate += parseFloat(1565.19);
					else if (shippingWeight > 28000 && shippingWeight <= 28500) me.shippingFlatRate += parseFloat(1591.85);
					else if (shippingWeight > 28500 && shippingWeight <= 29000) me.shippingFlatRate += parseFloat(1617.89);
					else if (shippingWeight > 29000 && shippingWeight <= 29500) me.shippingFlatRate += parseFloat(1644.86);
					else if (shippingWeight > 29500) me.shippingFlatRate += parseFloat(1670.9);
			
					shippingWeight = parseInt(shippingWeight,10) - 30000;
				}
			}
		}
	  };

        me.shipping = function(){
                if( parseInt(me.quantity,10)===0 )
                        return 0;
		    /*Calc shipping by weight*/
		    me.shippingRate();
		    var shippingWeight = 0;
		    var shippingBlocks = 0;
		    var shippingPrice = 0;

		    if ( me.shippingWeightMax > 0 ) {
		    	shippingBlocks = Math.ceil(parseFloat(me.weight) / parseFloat(me.shippingWeightMax));
		    	for (i=1; i<=shippingBlocks; i++) {
				if( shippingBlocks == 1)
					shippingWeight = parseInt(me.weight,10);
				else {
					if (i == shippingBlocks)
						shippingWeight = parseInt(me.weight,10) - (parseInt(me.shippingWeightMax,10) * (i-1));
					else
						shippingWeight = parseInt(me.shippingWeightMax,10);
				}

		    		shippingPrice += parseFloat(me.shippingWeightFlatRate);
		    		if ( shippingWeight > me.shippingWeightFlat) {
					shippingWeight = shippingWeight - parseInt(me.shippingWeightFlat,10);
					shippingWeight = Math.ceil(parseFloat(shippingWeight) / parseFloat(me.shippingWeightBlock)) * parseFloat(me.shippingWeightBlock);
					shippingPrice += parseInt(shippingWeight,10) / parseFloat(me.shippingWeightBlock) * me.shippingWeightBlockRate;
		    		}
		    	}
		    	shippingPrice = Math.round(shippingPrice*Math.pow(10,2))/Math.pow(10,2);
		    }
		    /*END Calc shipping by weight*/

                var shipping =  parseFloat(me.shippingFlatRate) +
                                                parseFloat(me.shippingTotalRate)*parseFloat(me.total) +
                                                parseFloat(me.shippingQuantityRate)*parseInt(me.quantity,10) +
                        				parseFloat(shippingPrice),
                        next;
                
                me.each(function(nextItem){             
                        if( nextItem.shipping ){
                                if( typeof nextItem.shipping == 'function' ){
                                        shipping += parseFloat(nextItem.shipping());
                                } else {
                                        shipping += parseFloat(nextItem.shipping);
                                }
                        }
                });

                return shipping;
        }

        me.initialize = function() {
                me.initializeView();
                me.load();
                me.update();
                me.ready();
        };

}

/********************************************************************************************************
 *                      Cart Item Object
 ********************************************************************************************************/

function CartItem() {
        while( simpleCart.items["c" + simpleCart.nextId] )      
                simpleCart.nextId++;
                
        this.id = "c" + simpleCart.nextId;
}


CartItem.prototype = {
        
        set : function ( field , value ){
                field = field.toLowerCase();
                if( typeof( this[field] ) !== "function" && field !== "id" ){
                        value = "" + value;
                        if( field == "quantity"){
                                value = value.replace( /[^(\d|\.)]*/gi , "" );
                                value = value.replace(/,*/gi, "");
                                value = parseInt(value,10);
                        } else if( field == "price" ){
                                value = value.replace( /[^(\d|\.)]*/gi, "");
                                value = value.replace(/,*/gi , "");
                                value = parseFloat( value );
                        } else if( field == "weight"){
                                value = value.replace( /[^(\d|\.)]*/gi , "" );
                                value = value.replace(/,*/gi, "");
                                value = parseInt(value,10);
                        }
                        if( typeof(value) == "number" && isNaN( value ) ){
                                error( "Improperly formatted input.");
                        } else {
                                if( typeof( value ) === "string" ){
                                        if( value.match(/\~|\=/) ){
                                                error("Special character ~ or = not allowed: " + value);
                                        }
                                        value = value.replace(/\~|\=/g, "");
                                }
                                this[field] = value;
                                this.checkQuantityAndPrice();
                        }
                } else {
                        error( "Cannot change " + field + ", this is a reserved field.");
                }
                simpleCart.update();
        },

        increment : function(){
                this.quantity = parseInt(this.quantity,10) + 1;
                simpleCart.update();
        },

        decrement : function(){
                if( parseInt(this.quantity,10) < 2 ){
                        this.remove();
                } else {
                        this.quantity = parseInt(this.quantity,10) - 1;
                        simpleCart.update();
                }
        },

        print : function () {
                var returnString = '',
                        field;
                simpleCart.each(this ,function(item,x,name){    
                        returnString+= escape(name) + "=" + escape(item) + "||";
                });
                return returnString.substring(0,returnString.length-2);
        },


        checkQuantityAndPrice : function() {

                if( !this.quantity || this.quantity == null || this.quantity == 'undefined'){ 
                        this.quantity = 1;
                        error('No quantity for item.');
                } else {
                        this.quantity = ("" + this.quantity).replace(/,*/gi, "" );
                        this.quantity = parseInt( ("" + this.quantity).replace( /[^(\d|\.)]*/gi, "") , 10);
                        if( isNaN(this.quantity) ){
                                error('Quantity is not a number.');
                                this.quantity = 1;
                        }
                }
        
        if( !this.weight || this.weight == null || this.weight == 'undefined'){ 
                        this.weight = 0;
                        error('No weight for item.');
                } else {
                        this.weight = ("" + this.weight).replace(/,*/gi, "" );
                        this.weight = parseInt( ("" + this.weight).replace( /[^(\d|\.)]*/gi, "") , 10);
                        if( isNaN(this.weight) ){
                                error('Weight is not a number.');
                                this.weight = 0;
                        }
                }

                if( !this.price || this.price == null || this.price == 'undefined'){
                        this.price=0.00;
                        error('No price for item or price not properly formatted.');
                } else {
                        this.price = ("" + this.price).replace(/,*/gi, "" );
                        this.price = parseFloat( ("" + this.price).replace( /[^(\d|\.)]*/gi, "") );
                        if( isNaN(this.price) ){
                                error('Price is not a number.');
                                this.price = 0.00;
                        }
                }
        },


        parseValuesFromArray : function( array ) {
                if( array && array.length && array.length > 0) {
                        for(var x=0, xlen=array.length; x<xlen;x++ ){

                                /* ensure the pair does not have key delimeters */
                                array[x] = array[x].replace(/\|\|/g, "| |");
                                array[x] = array[x].replace(/\+\+/g, "+ +");
                                if( array[x].match(/\~/) ){
                                        error("Special character ~ not allowed: " + array[x]);
                                }
                                array[x] = array[x].replace(/\~/g, "");
                                

                                /* split the pair and save the unescaped values to the item */
                                var value = array[x].split('=');
                                if( value.length>1 ){
                                        if( value.length>2 ){
                                                for(var j=2, jlen=value.length;j<jlen;j++){
                                                        value[1] = value[1] + "=" + value[j];
                                                }
                                        }
                                        this[ unescape(value[0]).toLowerCase() ] = unescape(value[1]);
                                }
                        }
                        return true;
                } else {
                        return false;
                }
        },

        remove : function() {
                simpleCart.remove(this.id);
                simpleCart.update();
        }
};



/********************************************************************************************************
 *                      Shelf Object for managing items on shelf that can be added to cart
 ********************************************************************************************************/

function Shelf(){
        this.items = {};
}
Shelf.prototype = { 
                
        readPage : function () {
                this.items = {};
                var newItems = getElementsByClassName( "simpleCart_shelfItem" ),
                        newItem;
                        me = this;
                
                for( var x = 0, xlen = newItems.length; x<xlen; x++){
                        newItem = new ShelfItem();
                        me.checkChildren( newItems[x] , newItem );
                        me.items[newItem.id] = newItem;
                }
        },

        checkChildren : function ( item , newItem) {
                if( !item.childNodes )
                        return;
                for(var x=0;item.childNodes[x];x++){

                        var node = item.childNodes[x];
                        if( node.className && node.className.match(/item_[^ ]+/) ){

                                var data = /item_[^ ]+/.exec(node.className)[0].split("_");

                                if( data[1] == "add" || data[1] == "Add" ){
                                        var tempArray = [];
                                        tempArray.push( node );
                                        var addFunction = simpleCart.Shelf.addToCart(newItem.id);
                                        simpleCart.addEventToArray( tempArray , addFunction , "click");
                                        node.id = newItem.id;
                                } else {
                                        newItem[data[1]]  = node;
                                }
                        }
                        if( node.childNodes[0] ){
                                this.checkChildren( node , newItem );
                        }
                }
        },

        empty : function () {
                this.items = {};
        },


        addToCart : function ( id ) {
                return function(){
                        if( simpleCart.Shelf.items[id]){
                                simpleCart.Shelf.items[id].addToCart();
                        } else {
                                error( "Shelf item with id of " + id + " does not exist.");
                        }
                };
        }
};


/********************************************************************************************************
 *                      Shelf Item Object
 ********************************************************************************************************/


function ShelfItem(){
        this.id = "s" + simpleCart.nextId++;
}

ShelfItem.prototype = {
        
        remove : function () {
                simpleCart.Shelf.items[this.id] = null;
        },

        addToCart : function () {
                var outStrings = [],
                        valueString,
                        field;
                        
                for( field in this ){
                        if( typeof( this[field] ) !== "function" && field !== "id" ){
                                valueString = "";

                                switch(field){
                                        case "price":
                                                if( this[field].value ){
                                                        valueString = this[field].value;
                                                } else if( this[field].innerHTML ) {
                                                        valueString = this[field].innerHTML;
                                                }
                                                /* remove all characters from price except digits and a period */
                                                valueString = valueString.replace( /[^(\d|\.)]*/gi , "" );
                                                valueString = valueString.replace( /,*/ , "" );
                                                break;
                                        case "image":
                                                valueString = this[field].src;
                                                break;
                                        default:
                                                if( this[field].value ){
                                                        valueString = this[field].value;
                                                } else if( this[field].innerHTML ) {
                                                        valueString = this[field].innerHTML;
                                                } else if( this[field].src ){
                                                        valueString = this[field].src;
                                                } else {
                                                        valueString = this[field];
                                                }
                                                break;
                                }
                                outStrings.push( field + "=" + valueString );
                        }
                }

                simpleCart.add( outStrings );
        }
};



/********************************************************************************************************
 * Thanks to Peter-Paul Koch for these cookie functions (http://www.quirksmode.org/js/cookies.html)
 ********************************************************************************************************/
function createCookie(name,value,days) {
        if (days) {
                var date = new Date();
                date.setTime(date.getTime()+(days*24*60*60*1000));
                var expires = "; expires="+date.toGMTString();
        }
        else var expires = "";
        value = value.replace(/\=/g, '~');
        document.cookie = name + "=" + escape(value) + expires + "; path=/";
}

function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0;i < ca.length;i++) {
                var c = ca[i];
                while (c.charAt(0)==' ') c = c.substring(1,c.length);
                if (c.indexOf(nameEQ) === 0){
                        var value = unescape(c.substring(nameEQ.length, c.length));
                        return value.replace(/\~/g, '=');
                } 
        }
        return null;
}

function eraseCookie(name) {
        createCookie(name,"",-1);
}


//*************************************************************************************************
/*
        Developed by Robert Nyman, http://www.robertnyman.com
        Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = function (className, tag, elm){
        if (document.getElementsByClassName) {
                getElementsByClassName = function (className, tag, elm) {
                        elm = elm || document;
                        var elements = elm.getElementsByClassName(className),
                                nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
                                returnElements = [],
                                current;
                        for(var i=0, il=elements.length; i<il; i+=1){
                                current = elements[i];
                                if(!nodeName || nodeName.test(current.nodeName)) {
                                        returnElements.push(current);
                                }
                        }
                        return returnElements;
                };
        }
        else if (document.evaluate) {
                getElementsByClassName = function (className, tag, elm) {
                        tag = tag || "*";
                        elm = elm || document;
                        var classes = className.split(" "),
                                classesToCheck = "",
                                xhtmlNamespace = "http://www.w3.org/1999/xhtml",
                                namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
                                returnElements = [],
                                elements,
                                node;
                        for(var j=0, jl=classes.length; j<jl; j+=1){
                                classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
                        }
                        try {
                                elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
                        }
                        catch (e) {
                                elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
                        }
                        while ((node = elements.iterateNext())) {
                                returnElements.push(node);
                        }
                        return returnElements;
                };
        }
        else {
                getElementsByClassName = function (className, tag, elm) {
                        tag = tag || "*";
                        elm = elm || document;
                        var classes = className.split(" "),
                                classesToCheck = [],
                                elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
                                current,
                                returnElements = [],
                                match;
                        for(var k=0, kl=classes.length; k<kl; k+=1){
                                classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
                        }
                        for(var l=0, ll=elements.length; l<ll; l+=1){
                                current = elements[l];
                                match = false;
                                for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
                                        match = classesToCheck[m].test(current.className);
                                        if (!match) {
                                                break;
                                        }
                                }
                                if (match) {
                                        returnElements.push(current);
                                }
                        }
                        return returnElements;
                };
        }
        return getElementsByClassName(className, tag, elm);
};


/********************************************************************************************************
 *      Helpers
 ********************************************************************************************************/


String.prototype.reverse=function(){return this.split("").reverse().join("");};
Number.prototype.withCommas=function(){var x=6,y=parseFloat(this).toFixed(2).toString().reverse();while(x<y.length){y=y.substring(0,x)+","+y.substring(x);x+=4;}return y.reverse();};
Number.prototype.toCurrency=function(){return(arguments[0]?arguments[0]:"$")+this.withCommas();};


/************ JSON *************/
var JSON;JSON||(JSON={});
(function(){function k(a){return a<10?"0"+a:a}function o(a){p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function(a){var c=r[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,j){var c,d,h,m,g=e,f,b=j[a];b&&typeof b==="object"&&typeof b.toJSON==="function"&&(b=b.toJSON(a));typeof i==="function"&&(b=i.call(j,a,b));switch(typeof b){case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if(!b)return"null";
e+=n;f=[];if(Object.prototype.toString.apply(b)==="[object Array]"){m=b.length;for(c=0;c<m;c+=1)f[c]=l(c,b)||"null";h=f.length===0?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if(i&&typeof i==="object"){m=i.length;for(c=0;c<m;c+=1)typeof i[c]==="string"&&(d=i[c],(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h);h=f.length===0?"{}":e?"{\n"+e+f.join(",\n"+e)+"\n"+g+"}":"{"+f.join(",")+
"}";e=g;return h}}if(typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()};var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,n,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;if(typeof JSON.stringify!=="function")JSON.stringify=function(a,j,c){var d;n=e="";if(typeof c==="number")for(d=0;d<c;d+=1)n+=" ";else typeof c==="string"&&(n=c);if((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return l("",
{"":a})};if(typeof JSON.parse!=="function")JSON.parse=function(a,e){function c(a,d){var g,f,b=a[d];if(b&&typeof b==="object")for(g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),f!==void 0?b[g]=f:delete b[g]);return e.call(a,d,b)}var d,a=String(a);q.lastIndex=0;q.test(a)&&(a=a.replace(q,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),typeof e==="function"?c({"":d},""):d;throw new SyntaxError("JSON.parse");}})();


/************ HTML5 Local Storage Support *************/
(function(){if(!this.localStorage)if(this.globalStorage)try{this.localStorage=this.globalStorage}catch(e){}else{var a=document.createElement("div");a.style.display="none";document.getElementsByTagName("head")[0].appendChild(a);if(a.addBehavior){a.addBehavior("#default#userdata");var d=this.localStorage={length:0,setItem:function(b,d){a.load("localStorage");b=c(b);a.getAttribute(b)||this.length++;a.setAttribute(b,d);a.save("localStorage")},getItem:function(b){a.load("localStorage");b=c(b);return a.getAttribute(b)},
removeItem:function(b){a.load("localStorage");b=c(b);a.removeAttribute(b);a.save("localStorage");this.length=0},clear:function(){a.load("localStorage");for(var b=0;attr=a.XMLDocument.documentElement.attributes[b++];)a.removeAttribute(attr.name);a.save("localStorage");this.length=0},key:function(b){a.load("localStorage");return a.XMLDocument.documentElement.attributes[b]}},c=function(a){return a.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,
"-")};a.load("localStorage");d.length=a.XMLDocument.documentElement.attributes.length}}})();


/********************************************************************************************************
 * error management
 ********************************************************************************************************/

function error( message ){
        try{
                console.log( message );
        }catch(err){
        //      alert( message );
        }
}


var simpleCart = new Cart();

if( typeof jQuery !== 'undefined' ) $(document).ready(function(){simpleCart.initialize();});
else if( typeof Prototype !== 'undefined') Event.observe( window, 'load', function(){simpleCart.initialize();});
else window.onload = simpleCart.initialize;